/*****************************************************************************
 *   Copyright (C) 2008 John Schember <john@nachtimwald.com>                 *
 *                                                                           *
 *   This file is part of niwbillmanager.                                    *
 *                                                                           *
 *   niwbillmanager is free software: you can redistribute it and/or         *
 *   modify it under the terms of the GNU General Public License as          *
 *   published by the Free Software Foundation, either version 3 of the      *
 *   License, or (at your option) any later version.                         *
 *                                                                           *
 *   niwbillmanager is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with niwbillmanager. If not, see                                  *
 *   <http://www.gnu.org/licenses/>.                                         *
 *****************************************************************************/

#ifndef NIWBILLMANAGER_H
#define NIWBILLMANAGER_H

#include <QHash>
#include <QStringList>

#include <backendinterface.h>
#include <billitem.h>
#include <transaction.h>

class Backend;
class BackendManager;
class DataStore;

/**
 * The niwbillmanager library.
 * Holds the bill items in memory. Manages the backends. Allows for
 * manipulaion of bill items on disk though any front end using this library.
 *
 * When getting bill items it is recommended to use start functions and get the
 * results with getNextBillItem than to use the non start equivalent functions.
 */
class NiwBillManager
{
    public:
        NiwBillManager();
        ~NiwBillManager();

        /**
         * Check if a backend is not be loaded.
         * The only time this will return false is when there are no backends
         * avalible to use. This library will not work correctly without a
         * backend. Check this after loading the library. If it does not
         * return true than unload the library and do not continue with
         * execution of the application. The first backend found is loaded
         * in the constructor of this library.
         * @return true if a backend was loaded.
         */
        bool isBackendLoaded();
        /**
         * Gets a listing of all avalible backends.
         * @return A list of all avaliable backends.
         */
        QHash<QString, Backend *> getAvaliableBackends() const;
        /**
         * Sets the backend to use based on the name of the backend.
         * @param backendName The name of the backend to use.
         * @return Ture if backend successfully set. Otherwise the backend is
         * set to the first backend returned by getAvaliableBackends.
         * @see getAvaliableBackends
         */
        bool setBackend(QString backendName);
        /**
         * Gets the name of the backend in use.
         * @return The name of the backend.
         */
        QString getBackendName();
        /**
         * Gets the description of the backend in use.
         * @return The description of the backend.
         */
        QString getBackendDescription();
        /**
         * Gets the description of the specified backend.
         * @param backendName The name of the backend.
         * @return The description of the backend.
         */
        QString getBackendDescription(QString backendName);
        /**
         * Gets the version of the backend in use.
         * @return The version of the backend.
         */
        QString getBackendVersion();
        /**
         * Gets the version of the specified backend.
         * @param backendName The name of the backendName.
         * @return The version of the backend.
         */
        QString getBackendVersion(QString backendName);
        /**
         * Gets the file extension of the current backend.
         * Only works with local backends.
         * @return The default file extension.
         */
        QString getBackendFileExtenstion();
        /**
         * Check if the backend uses a remote connection to read and write.
         * @return True if the backend utalizes a remote connection.
         */
        bool isBackendRemote();
        /**
         * Check if the specified backend uses a remote connection to read and
         * write.
         * @param backendName The name of the backend.
         * @return True if the backend utalizes a remote connection.
         */
        bool isBackendRemote(QString backendName);

        /**
         * Creates a new collection in memory.
         * Be sure to save the current collection before calling this. The old
         * collection is lost.
         */
        void newCollection();
        /**
         * Loads a collection into memory.
         * @param location The location of the collection.
         * Can be either a local file or a network address depending on the
         * backend implementation.
         * @param username Username within the associated collection. This is
         * for collections that have multiple users.
         * @param loginname The username to login for a remote connection.
         * @param password The password associated wtih remote connection
           login.
         * @return True if the collection was successfully opened.
         */
        bool loadCollection(const QString &location,
            const QString &username="", const QString &loginname="",
            const QString &password="");
        /**
         * Save the changes to the collection.
         * The collection can either be a local file or a remote connection
         * of some kind.
         * @param location The location of the collection.
         * Can be either a local file or a network address depending on the
         * backend implementation.
         * @param username Username within the associated collection. This is
         * for collections that have multiple users.
         * @param loginname The username to login for a remote connection.
         * @param password The password associated wtih remote connection
           login.
         * @return True if the collection was sucessfully saved.
         */
        bool saveCollection(const QString &location,
            const QString &username="", const QString &loginname="",
            const QString &password="");
        /**
         * Save the entire collection.
         * The collection can either be a local file or a remote connection
         * of some kind.
         * @param location The location of the collection.
         * Can be either a local file or a network address depending on the
         * backend implementation.
         * @param username Username within the associated collection. This is
         * for collections that have multiple users.
         * @param loginname The username to login for a remote connection.
         * @param password The password associated wtih remote connection
           login.
         * @return True if the collection was sucessfully saved.
         */
        bool saveAsCollection(const QString &location,
            const QString &username="", const QString &loginname="",
            const QString &password="");
        /**
         * Check if there are unsaved items that can be saved to disk.
         * @return True if there are changes in the transaction log.
         */
        bool shouldSave();

        /**
         * Gets a listing of all tags used by bill items.
         * @return A listing of all tags.
         */
        QSet<QString> getAllTags();
        /**
         * Gets all tags associated with a bill item.
         * @param billId The id associated with a bill item.
         * @return A list of all the tags associated with the bill item.
         */
        QSet<QString> getTags(QString billId);
        /**
         * Gets a list of bill items having any of the given tags
         * @param tags The list of tags to search for bill items with.
         * @return A list of bill items.
         */
        QSet<BillItem> getBillItemsFromTags(QSet<QString> tags);
        /**
         * Starts a query to get bill items based on a list of tags.
         * @see hasMoreBillItems
         * @see getNextBillItem
         */
        void startGetBillItemsFromTags(QSet<QString> tags);
        /**
         * Gets all bill items that do not have any tags.
         * @return A list of untagged bill items.
         */
        QSet<BillItem> getBillItemsWithoutTags();
        /**
         * Starts a query to get bill items without tags.
         * @see hasMoreBillItems
         * @see getNextBillItem
         */
        void startGetBillItemsWithoutTags();

        /**
         * Creates a new bill item.
         * @param billItem The bill item to add.
         * @return The id created for the bill item.
         */
        QString newBillItem(BillItem billItem);
        /**
         * Changes the bill item information.
         * Uses the id of billItem to determine which bill item to act upon.
         * Changes the stored bill item to be the same as the information
         * provided in the billItem param. This will change all information
         * except for the id which cannot be changed and is used to referenced
         * the bill item to change.
         * @param billItem The bill item changes.
         * @return True if the item was successfully updated.
         */
        bool modifyBillItem(BillItem billItem);
        /**
         * Deletes a bill item.
         * @param billId The id of the bill item to delete.
         */
        bool deleteBillItem(QString billId);
        /**
         * Gets the bill item referenced by id.
         * @param billId The id for the bill item.
         * @param billItem A reference to store the retrieved bill item in.
         * @return The bill item.
         */
        bool getBillItemById(QString billId, BillItem &billItem);
        /**
         * Gets all bill items.
         * @return A list of all bill items.
         */
        QSet<BillItem> getAllBillItems();
        /**
         * Starts a query to get all bill items.
         * @see hasMoreBillItems
         * @see getNextBillItem
         */
        void startGetAllBillItems();
        /**
         * Searchs for bill items that match query in all fields..
         * @param query What to match bill items with.
         * @param amountDue Search in amount due.
         * @param autoPay Search for auto pay bills.
         * @param nonAutoPay Search non auto pay bills.
         * @param dateDue Search in date due.
         * @param overDue Search for over due bills only.
         * @param payee Search in payee.
         * @param paymentLocation Search in payment location.
         * @param paymentMethod Search in payment method.
         * @param paymentRecurringPeriod Search in payment recurring period.
         * @param recurringOnly Search for recurring bills only.
         * @param nonRecurring Search for non-recurring bills.
         * @param paid Search for paid bills.
         * @param unpaid Search for unpaid bills.
         * @param name Search in the bill name.
         * @param notes Search in notes.
         * @param tags Search in tags.
         */
        void startSearchBillItemsAnd(QSet<QString> query,
            bool amountDue=true, bool autoPay=true, bool nonAutoPay=true,
            bool dateDue=true, bool payee=true, bool paymentLocation=true,
            bool paymentMethod=true, bool paymentRecurringPeriod=true,
            bool recurringOnly=true, bool nonRecurring=true, bool paid=true,
            bool unpaid=true, bool name=true, bool notes=true, bool tags=true);
        /**
         * Searchs for bill items that match query in any field..
         * @param query What to match bill items with.
         * @param amountDue Search in amount due.
         * @param autoPay Search for auto pay bills.
         * @param nonAutoPay Search non auto pay bills.
         * @param dateDue Search in date due.
         * @param overDue Search for over due bills only.
         * @param payee Search in payee.
         * @param paymentLocation Search in payment location.
         * @param paymentMethod Search in payment method.
         * @param paymentRecurringPeriod Search in payment recurring period.
         * @param recurringOnly Search for recurring bills only.
         * @param nonRecurring Search for non-recurring bills.
         * @param paid Search for paid bills.
         * @param unpaid Search for unpaid bills.
         * @param name Search in the bill name.
         * @param notes Search in notes.
         * @param tags Search in tags.
         */
        void startSearchBillItemsOr(QSet<QString> query,
            bool amountDue=true, bool autoPay=true, bool nonAutoPay=true,
            bool dateDue=true, bool payee=true, bool paymentLocation=true,
            bool paymentMethod=true, bool paymentRecurringPeriod=true,
            bool recurringOnly=true, bool nonRecurring=true, bool paid=true,
            bool unpaid=true, bool name=true, bool notes=true, bool tags=true);

        /**
         * Checks if a bill item transaction transaction has bill items that
         * have not been retrieved.
         * @return True if there are more bill items that can be retrieved.
         */
        bool hasMoreBillItems();
        /**
         * Gets the next bill item in a bill item transaction.
         * @return The next bill item.
         */
        bool getNextBillItem(BillItem &billItem);

        /**
         * Checks if previous changes can be undone.
         * @return True if changes can be undone.
         */
        bool canUndoChange();
        /**
         * Checks if changes can be redone.
         * @return True if changes can be redone.
         */
        bool canRedoChange();
        /**
         * Undo the last change.
         * @return True on success
         */
        bool undoChange();
        /**
         * Undo the last change.
         * @param transaction The change made.
         * @return True on success
         */
        bool undoChange(Transaction &transaction);
        /**
         * Redo (un-undo) the the last change.
         * @param transaction The change made.
         * @return True on success.
         */
        bool redoChange();
        /**
         * Redo (un-undo) the the last change.
         * @param transaction The change made.
         * @return True on success.
         */
        bool redoChange(Transaction &transaction);

        QString getLastErrorMessage();

    private:
        QHash<QString, TransactionType::TransactionTypes>
            createShortTransactionLog();

        BackendManager *m_backendManager;
        DataStore *m_dataStore;

        QString m_errorMessage;
};

#endif /* NIWBILLMANAGER_H */
